home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d18 / mou105.arc / MOU.PAS < prev    next >
Pascal/Delphi Source File  |  1991-09-29  |  29KB  |  1,025 lines

  1. unit mou;
  2. interface
  3.  
  4. {****************************************************************************
  5.  * PROJECT:  Mouse routines with 'real' graphic cursor in text mode.
  6.  *****************************************************************************
  7.  * MODULE:  MOU.PAS
  8.  *****************************************************************************
  9.  * DESCRIPTION:
  10.  *   Pascal source file for the mouse routines.  Combined near-literal
  11.  *   translation of MOU.H and MOU.C
  12.  *
  13.  *****************************************************************************
  14.  * MODIFICATION NOTES:
  15.  *    Date     Author Comment
  16.  * 26-Oct-1990   dk   Initial file.
  17.  * 07-Jan-1991   dk   Fixed bugs and set up for release to Usenet.
  18.  * 10-Jan-1991   djm  Translation to Turbo Pascal
  19.  *****************************************************************************
  20.  *
  21.  * DISCLAIMER:
  22.  *
  23.  * Programmers may incorporate any or all code into their programs,
  24.  * giving proper credit within the source. Publication of the
  25.  * source routines is permitted so long as proper credit is given
  26.  * to Dave Kirsch.
  27.  *
  28.  * Copyright (C) 1990, 1991 by Dave Kirsch.  You may use this program, or
  29.  * code or tables extracted from it, as desired without restriction.
  30.  * I can not and will not be held responsible for any damage caused from
  31.  * the use of this software.
  32.  *
  33.  *****************************************************************************
  34.  * This source works with Turbo Pascal 6.0.
  35.  ****************************************************************************}
  36.  
  37. {*************************************************}
  38. { Mon 07-Jan-1991 - dk                            }
  39. {                                                 }
  40. {  Variables and defines for the mouse routines.  }
  41. {                                                 }
  42. {*************************************************}
  43.  
  44. { Size of mouse "click" ahead buffer. }
  45. const
  46.   MOUSEBUFFERSIZE = 16;
  47.  
  48. { Bit defines for mouse driver function 12 -- define handler. }
  49.   MOUSEMOVE      =1;
  50.   LEFTBPRESS     =2;
  51.   LEFTBRELEASE   =4;
  52.   RIGHTBPRESS    =8;
  53.   RIGHTBRELEASE =16;
  54.   MIDBPRESS     =32;
  55.   MIDBRELEASE   =64;
  56.  
  57.   LEFTBDOWN  =1;
  58.   RIGHTBDOWN =2;
  59.   MIDBDOWN   =4;
  60.  
  61. { Shift states for byte a 0:417h
  62.    bit 7 =1 INSert active
  63.    bit 6 =1 Caps Lock active
  64.    bit 5 =1 Num Lock active
  65.    bit 4 =1 Scroll Lock active
  66.    bit 3 =1 either Alt pressed
  67.    bit 2 =1 either Ctrl pressed
  68.    bit 1 =1 Left Shift pressed
  69.    bit 0 =1 Right Shift pressed
  70. }
  71.  
  72.   SHIFT_RIGHTSHIFT =$01;
  73.   SHIFT_LEFTSHIFT  =$02;
  74.   SHIFT_SHIFT      =$03; { Either shift key. }
  75.   SHIFT_CTRL       =$04;
  76.   SHIFT_ALT        =$08;
  77.   SHIFT_SCROLLLOCK =$10;
  78.   SHIFT_NUMLOCK    =$20;
  79.   SHIFT_CAPSLOCK   =$40;
  80.   SHIFT_INS        =$80;
  81.  
  82. { Mouse information record }
  83. type
  84.   minforectype = record
  85.     buttonstat : word;
  86.     cx, cy : integer;
  87.     shiftstate : byte;
  88.   end;
  89.  
  90. {  MOUINFOREC = minforectype; }
  91.  
  92. const
  93.   mousehidden : word = 0;           { Is the mouse on? Additive flag }
  94.   mouseinstalled : boolean = FALSE; { Is the mouse installed? }
  95.  
  96. var
  97.   mousex, mousey : integer; { Mouse coordinates in characters. }
  98.   mousepx, mousepy : word;  { Mouse pixel coordinates - not interfaced in C
  99.                               version }
  100.  
  101. { Initialize the mouse routines -- must be called. }
  102. procedure MOUinit;
  103.  
  104. { Deinitialize the mouse routines -- must be called on shutdown.
  105.    Failure to call it will most likely result in a system crash if the mouse
  106.    is moved. }
  107. procedure MOUdeinit;
  108.  
  109. { Hide the mouse cursor }
  110. procedure MOUhide;
  111.  
  112. { Hide the mouse cursor if it moves or is in a specific rectangular region
  113.    of the screen. }
  114. procedure MOUconditionalhide(x1, y1, x2, y2:integer);
  115.  
  116. { Show the mouse cursor }
  117. procedure MOUshow;
  118.  
  119. { return TRUE if there are events waiting in the buffer. }
  120. function MOUcheck:boolean;
  121.  
  122. { look at the next event in the buffer, but don't pull it out. }
  123. procedure MOUpreview(var mouinforec:minforectype);
  124.  
  125. { get and remove next event from the buffer. }
  126. procedure MOUget(var mouinforec:minforectype);
  127.  
  128. { return the current status of the mouse buttons (see defines above). }
  129. function MOUbuttonstatus:word;
  130.  
  131. implementation
  132.  
  133. uses
  134.   Crt;
  135.  
  136. { Routine to emulate w++ for words }
  137. function postinc(var w:word):word;
  138. begin
  139.   postinc := w;
  140.   inc(w);
  141. end;
  142.  
  143. const
  144.   HEIGHT =16;
  145.  
  146. const
  147.   mbufin : integer = 0;
  148.   mbufout: integer = 0; { Mouse buffer pointers }
  149.  
  150.   mousefreeze:integer = 0;           { Is mouse frozen in place? }
  151.  
  152. var
  153.   mbuf : array [0..MOUSEBUFFERSIZE-1] of minforectype; { Mouse buffer }
  154.  
  155. { Save information for non EGA/VGA }
  156.   oldword : word;
  157.   newword : word;
  158. const
  159.   saved : boolean = FALSE;
  160. var
  161.   oldmx, oldmy : word;
  162.  
  163. { Save information for EGA/VGA displays }
  164. const
  165.   egavga : boolean = FALSE; { Do we have an EGA/VGA adapter? }
  166. var
  167.   savechars : array [0..3-1] of array[0..3-1] of byte;
  168.               { The saved characters we overwrote }
  169. const
  170.   mousecursormask : array[0..HEIGHT-1] of longint =  (
  171.   $00000000,  {0000000000000000}
  172.   $40000000,  {0100000000000000}
  173.   $60000000,  {0110000000000000}
  174.   $70000000,  {0111000000000000}
  175.   $78000000,  {0111100000000000}
  176.   $7c000000,  {0111110000000000}
  177.   $7e000000,  {0111111000000000}
  178.   $7f000000,  {0111111100000000}
  179.   $7f800000,  {0111111110000000}
  180.   $7f000000,  {0111111100000000}
  181.   $7c000000,  {0111110000000000}
  182.   $46000000,  {0100011000000000}
  183.   $06000000,  {0000011000000000}
  184.   $03000000,  {0000001100000000}
  185.   $03000000,  {0000001100000000}
  186.   $00000000   {0000000000000000}
  187. );
  188.  
  189. mousescreenmask : array[0..HEIGHT-1] of longint =  (
  190.   $3fffffff,  {0011111111111111}
  191.   $1fffffff,  {0001111111111111}
  192.   $0fffffff,  {0000111111111111}
  193.   $07ffffff,  {0000011111111111}
  194.   $03ffffff,  {0000001111111111}
  195.   $01ffffff,  {0000000111111111}
  196.   $00ffffff,  {0000000011111111}
  197.   $007fffff,  {0000000001111111}
  198.   $003fffff,  {0000000000111111}
  199.   $007fffff,  {0000000001111111}
  200.   $01ffffff,  {0000000111111111}
  201.   $10ffffff,  {0001000011111111}
  202.   $b0ffffff,  {1011000011111111}
  203.   $f87fffff,  {1111100001111111}
  204.   $f87fffff,  {1111100001111111}
  205.   $fcffffff   {1111110011111111}
  206. );
  207.  
  208. var
  209.   chardefs : array[0..(32 * 9-1)] of byte; { 9 character definitons. }
  210.   points : word;           { change by djm! }
  211.  
  212. const
  213.   conditionalhidemouse : boolean = FALSE;
  214. var
  215.   conx1, cony1, conx2, cony2 : word;
  216.  
  217.   vseg: word; { Segment of video ram. }
  218.   mcols, mrows : word;
  219.   savevmode : byte;
  220.  
  221.   maxx, maxy : integer;
  222.  
  223. const
  224.   desqview : boolean = FALSE;
  225.  
  226. procedure POKEATTRIB(x, y : word; a: byte);
  227. begin
  228.   mem[vseg: (y) * (mcols * 2) + ((x) shl 1) + 1] := a;
  229. end;
  230.  
  231. function PEEKATTRIB(x, y: word):byte;
  232. begin
  233.   PEEKATTRIB := mem[vseg: (y) * (mcols * 2) + ((x) shl 1) + 1]
  234. end;
  235.  
  236. procedure pokeb(a, b:word;c : byte);
  237. begin
  238.   mem[a:b] := c
  239. end;
  240.  
  241. function peekb(a,b:word):byte;
  242. begin
  243.   peekb := mem[a:b];
  244. end;
  245.  
  246. var
  247.   BIOS_POINTS : byte absolute $0000:$0485;
  248.   COLS : byte absolute $0040:$004A;
  249.   ROWS : byte absolute $0040:$0084;
  250.  
  251. const
  252.   DEFCHAR = $d0;
  253.  
  254. {*******************************************************************}
  255. { Mon 07-Jan-1991 - dk                                              }
  256. {                                                                   }
  257. {  Plot the cursor on the screen, save background, draw grid, etc.  }
  258. {                                                                   }
  259. {*******************************************************************}
  260. procedure plotegavgacursor(func:integer);
  261. var
  262.   off,
  263.   width, height, i, j,
  264.   disp,
  265.   x, y : word;
  266. const
  267.   lsavex:integer = 0;
  268.   lsavey:integer = 0;
  269.  
  270. begin
  271.   case (func) of
  272.     0 : begin{ erase grid, put back save info }
  273.       x := lsavex;
  274.       y := lsavey;
  275.       end;
  276.     1 : begin{ draw grid }
  277.       x := mousex;
  278.       y := mousey;
  279.       end;
  280.     2 : begin { save grid }
  281.       x := mousex;
  282.       lsavex := x;
  283.       y := mousey;
  284.       lsavey := y;
  285.       end;
  286.   end;
  287.  
  288.   width := mcols - x;
  289.   if (width > 3) then
  290.     width := 3;
  291.   height := mrows - y;
  292.   if (height > 3) then
  293.     height := 3;
  294.  
  295.   off := y * (mcols * 2) + x * 2;
  296.   disp := (mcols * 2) - width * 2;
  297.  
  298.   case (func) of
  299.     0 : begin { erase grid, put back save info }
  300.       for i := 0 to height-1 do
  301.       begin
  302.         for j := 0 to width-1 do
  303.         begin
  304.           mem[vseg:off] := savechars[i][j];
  305.           inc(off,2);
  306.         end;
  307.         inc(off,disp);
  308.       end;
  309.     end;
  310.     1 : begin{ draw grid. }
  311.       for i := 0 to height-1 do
  312.       begin
  313.         for j := 0 to width-1 do
  314.         begin
  315.           mem[vseg:off] := DEFCHAR + i * 3 + j;
  316.           inc(off,2);
  317.         end;
  318.         inc(off,disp);
  319.       end;
  320.     end;
  321.     2 : begin{ save grid. }
  322.       for i := 0 to height-1 do
  323.       begin
  324.         for j := 0 to width-1 do
  325.         begin
  326.           savechars[i][j] := mem[vseg:off];
  327.           inc(off, 2);
  328.         end;
  329.         inc(off,disp);
  330.       end;
  331.     end;
  332.   end
  333. end;
  334.  
  335. procedure drawegavgacursor;
  336. var
  337.   off : word;
  338.   i, j : integer;
  339.   s1, s2, s3 : word;
  340.   defs : ^longint;
  341.   masks : ^longint;
  342.   shift : word;
  343.   addmask : longint;
  344. label
  345.   notmono;
  346. begin
  347.  
  348.   plotegavgacursor(2); { Save current grid that is there. }
  349.  
  350.   { Time for some assembler.  Program the EGA/VGA Sequencer and Graphics
  351.      Controller for direct access to the character definition tables.
  352.      Then read in the definitions for the characters we are changing, AND
  353.      the screen mask, then OR the cursor mask to them.  Then copy those
  354.      defintions into the location of the mouse cursor defintions
  355.      and set the Sequencer and Graphics Controller back to normal <whew!>.
  356.   }
  357.  
  358.   { Program the Sequencer }
  359.  
  360.   asm
  361.     pushf; { Disable interrupts }
  362.     cli;
  363.     mov dx, 3c4h; { Sequencer port address }
  364.     mov ax, 0704h; { Sequential addressing }
  365.     out dx, ax;
  366.  
  367.   { Program the Graphics Controller }
  368.     mov dx, 3ceh; { Graphics Controller port address }
  369.     mov ax, 0204h; { Select map 2 for CPU reads }
  370.     out dx, ax;
  371.     mov ax, 0005h; { Disable odd-even addressing }
  372.     out dx, ax;
  373.     mov ax, 0406h; { Map starts at A000:0000 (64K mode) }
  374.     out dx, ax;
  375.     popf;
  376.   end;
  377.  
  378.   { Ok, now we have direct access to the character defintion tables, copy
  379.      over the defintions for the characters we are changing }
  380.  
  381.   off := 0;
  382.   for i := 0 to 3-1 do   { Note change in loop logic!  -djm }
  383.   begin{ Grid is three characters high. }
  384.     s1 := savechars[i    ,0] * 32;
  385.     s2 := savechars[i    ,1] * 32;
  386.     s3 := savechars[i    ,2] * 32;
  387.     for j := 0 to points-1 do
  388.     begin
  389.       inc(off); { 4th byte, that we don't need. }
  390.       chardefs[postinc(off)] := mem[$a000:postinc(s3)];
  391.       chardefs[postinc(off)] := mem[$a000:postinc(s2)];
  392.       chardefs[postinc(off)] := mem[$a000:postinc(s1)];
  393.     end;
  394.   end;
  395.  
  396.   { Ok, we've got the defintions for the characters that we are drawing the
  397.      cursor on.  AND the screen mask and OR the cursor mask to them, thereby
  398.      'drawing' the cursor.  Since the cursor is 16 pixels wide and 16 pixels
  399.      high, we have to save a 3 by 3 character grid where the mouse cursor is
  400.      going.  We use dwords (32 bits) to do the bit AND and OR.  This could
  401.      be made alot faster on a 386 by using 32 bit registers. }
  402.  
  403.   shift := mousepx mod 8;
  404.   addmask := $ff000000 shl (8 - shift);
  405.  
  406.   masks := @mousescreenmask;
  407.   defs := @chardefs[(mousepy mod points)*sizeof(longint)];
  408.   for i := 0 to HEIGHT-1 do
  409.   begin
  410.     defs^ := defs^ and ((masks^ shr shift) or addmask);
  411.     inc(word(defs),sizeof(longint));
  412.     inc(word(masks),sizeof(longint));
  413. {   *defs++ &= (*masks++ >> shift) | addmask; }
  414.   end;
  415.  
  416.   masks := @mousecursormask;
  417.   defs := @chardefs[(mousepy mod points)*sizeof(longint)];
  418.   for i := 0 to HEIGHT-1 do
  419.   begin
  420.     defs^ := defs^ or (masks^ shr shift);
  421.     inc(word(defs),sizeof(longint));
  422.     inc(word(masks),sizeof(longint));
  423. {    *defs++ |= *masks++ >> shift;  }
  424.   end;
  425.   { Ok, Everything is setup, now copy the modifed character definitions
  426.      to their new location. }
  427.  
  428.   asm
  429.     mov dx, 3c4h; { Sequencer port address }
  430.     mov ax, 0402h; { CPU writes only to map 2 }
  431.     out dx, ax;
  432.   end;
  433.  
  434.   off := 0;
  435.   for i:=0 to 3-1 do   { Logic change here!  -djm }
  436.   begin
  437.   { Grid is three characters high. }
  438.     s1 := (DEFCHAR + 3*i    ) * 32;
  439.     s2 := (DEFCHAR + 3*i + 1) * 32;
  440.     s3 := (DEFCHAR + 3*i + 2) * 32;
  441.     for j := 0 to points-1 do
  442.     begin
  443.       inc(off); { 4th byte, that we don't need. }
  444.       mem[$a000:postinc(s3)] := chardefs[postinc(off)];
  445.       mem[$a000:postinc(s2)] := chardefs[postinc(off)];
  446.       mem[$a000:postinc(s1)] := chardefs[postinc(off)];
  447.     end;
  448.   end;
  449.  
  450.   { Ok, put the Sequencer and Graphics Controller back to normal }
  451.  
  452.   { Program the Sequencer }
  453.   asm
  454.     pushf; { Disable interrupts }
  455.     cli;
  456.     mov dx, 3c4h; { Sequencer port address }
  457.     mov ax, 0302h; { CPU writes to maps 0 and 1 }
  458.     out dx, ax;
  459.     mov ax, 0304h; { Odd-even addressing }
  460.     out dx, ax;
  461.  
  462.   { Program the Graphics Controller }
  463.     mov dx, 3ceh; { Graphics Controller port address }
  464.     mov ax, 0004h; { Select map 0 for CPU reads }
  465.     out dx, ax;
  466.     mov ax, 1005h; { Enable odd-even addressing }
  467.     out dx, ax;
  468.     sub ax, ax;
  469.     mov es, ax; { Segment 0 }
  470.     mov ax, 0e06h; { Map starts at B800:0000 }
  471.     mov bl, 7;
  472.     cmp es:[49h], bl; { Get current video mode }
  473.     jne notmono;
  474.     mov ax, 0806h; { Map starts at B000:0000 }
  475. notmono:
  476.     out dx, ax;
  477.     popf;
  478.   end;
  479.   { Ok, now put the bytes on the screen }
  480.  
  481.   plotegavgacursor(1); { Plot the new grid on the screen. }
  482. end;
  483.  
  484. {*****************************************************}
  485. { 27-Oct-1990 - dk                                    }
  486. {                                                     }
  487. {  This function checks for the presense of EGA/VGA.  }
  488. {                                                     }
  489. {*****************************************************}
  490. function isegavga:boolean;
  491. label
  492.   isvga,checkega;
  493. begin
  494.   asm
  495.     mov ax, 1a00h; { ROM BIOS video function 1ah -- Read Display Code }
  496.     int 10h;
  497.     cmp ah, 1ah; { Is this call supported? }
  498.     je checkega; { Not supported }
  499.     cmp bl, 7; { VGA w/monochrome display? }
  500.     je isvga; { Yup. }
  501.     cmp bl, 8; { VGA w/color display? }
  502.     jne checkega; { Nope }
  503.   end;
  504. isvga:
  505.   isegavga := TRUE; { EGA/VGA is installed }
  506.   exit;
  507. checkega:
  508.   asm
  509.     mov ah, 12h; { EGA BIOS function }
  510.     mov bl, 10h;
  511.     int 10h;
  512.     cmp bl, 10h; { Is EGA BIOS present? }
  513.     jne isvga; { There is an EGA in the system. }
  514.   end;
  515.   isegavga := FALSE; { Not EGA or VGA in system. }
  516. end;
  517.  
  518. {**********************************************}
  519. { 26-Oct-1990 - dk                             }
  520. {                                              }
  521. {  Mouse handler -- called from mouse driver.  }
  522. {                                              }
  523. {**********************************************}
  524. {$S-} { Turn off stack checking }
  525. procedure mousehandler; far;
  526. { This function is called whenever a button is pressed.  Do not call this
  527.    function directly!!
  528. }
  529. var
  530.   conditionmask:integer;
  531. begin
  532.   { Get our data segment }
  533.   asm
  534.     push ds
  535.     push ax
  536.     mov ax, seg @data
  537.     mov ds, ax
  538.     pop ax
  539.  
  540.     mov conditionmask,ax
  541.   end;
  542.  
  543.   if (mousefreeze = 0) then
  544.   begin
  545.     { save mouse info passed to us from driver }
  546.     asm
  547.       mov mousepx, cx  { note change by djm }
  548.       mov mousepy, dx
  549.     end;
  550.     mousex := mousepx div 8; { Characters are 8 pixels wide }
  551.     mousey := mousepy div points; { Scale mousey down }
  552.  
  553.     { See if the mouse has moved. }
  554.     if (conditionmask and MOUSEMOVE) <> 0 then
  555.     begin
  556.       if (saved) then
  557.       begin
  558.         if (egavga) then
  559.           plotegavgacursor(0)
  560.         else
  561.           POKEATTRIB(oldmx, oldmy, oldword);
  562.         saved := FALSE;
  563.       end;
  564.  
  565.       if (mousehidden=0) and conditionalhidemouse then{ Check to see if we need to hide }
  566.         if (mousex >= conx1) and (mousex <= conx2) and
  567.            (mousey >= cony1) and (mousey <= cony2) then
  568.         begin
  569.           inc(mousehidden);
  570.           conditionalhidemouse := FALSE;
  571.         end;
  572.  
  573.       if (mousehidden=0) then
  574.       begin
  575.         if (egavga) then
  576.           drawegavgacursor
  577.         else
  578.         begin
  579.           oldword := PEEKATTRIB(mousex, mousey);
  580.           asm
  581.             mov ax,[oldword];  { Prepare to rotate attrib byte }
  582.             and al, 0f7h; { Clear high bit }
  583.             mov cl, 4   { We want to rotate 4 bits }
  584.             rol al, cl  { Rotate it }
  585.             mov newword,AX;
  586.           end;
  587.  
  588.           POKEATTRIB(mousex, mousey, newword); { Write out new mouse cursor }
  589.         end;
  590.  
  591.         oldmx := mousex;
  592.         oldmy := mousey;
  593.         saved := TRUE;
  594.  
  595.       end
  596.     end
  597.   end;
  598.  
  599.   { Now, see if a mouse button was whacked }
  600.   if (conditionmask and (not MOUSEMOVE)) <> 0 then
  601.     if (((mbufin + 1) mod MOUSEBUFFERSIZE) = mbufout) then
  602.     begin { Buffer full? }
  603.       sound(1760); { Make some noise. }
  604.       delay(10);
  605.       nosound;
  606.     end else begin
  607.       mbuf[mbufin].buttonstat := conditionmask and (not MOUSEMOVE);
  608.       mbuf[mbufin].cx := mousex;
  609.       mbuf[mbufin].cy := mousey;
  610.       mbuf[mbufin].shiftstate := mem[0:$417]; { Get shift byte }
  611.       mbufin := (mbufin + 1) mod MOUSEBUFFERSIZE;
  612.     end;
  613.  
  614.   asm
  615.     pop ds;
  616.   end;
  617. end;
  618. {$S+} { Turn on stack checking }
  619.  
  620. {**********************************}
  621. { 26-Oct-1990 - dk                 }
  622. {                                  }
  623. {  Initialize the mouse routines.  }
  624. {                                  }
  625. {**********************************}
  626. procedure MOUinit;
  627. var
  628.   v:byte;
  629. label
  630.   notdv;
  631. begin
  632.  
  633.   asm
  634.     sub ax,ax;    { Mouse driver function 0 -- reset and detect }
  635.     int 33h
  636.     mov mouseinstalled, AL;
  637.   end;
  638.  
  639.   if (mouseinstalled) then
  640.   begin { If a mouse is installed then activate driver }
  641.  
  642.     inc(mousefreeze); { Make sure handler doesn't do things, yet }
  643.  
  644.     asm
  645.       mov ax,0F00h;
  646.       int 10h;
  647.       mov v,al;
  648.     end;
  649.  
  650.     if (v = 7) then
  651.     begin
  652.       vseg := $b000;
  653.     end else begin
  654.       vseg := $b800;
  655.       v := 3;
  656.     end;
  657.  
  658.     if (ROWS = 0) then
  659.     begin { No value, assume 80x25. }
  660.       mrows := 25;
  661.       mcols := 80;
  662.       points := 8;
  663.     end else begin
  664.       mrows := ROWS + 1;
  665.       mcols := COLS;
  666.       points := BIOS_POINTS;
  667.     end;
  668.  
  669.     { Check to see if we are running in DESQview.  If so, don't try to
  670.        use the 'true' EGA/VGA cursor (DV doesn't like it at ALL). }
  671.  
  672.     asm
  673.       mov ax, 2b01h;
  674.       mov cx, 4445h;
  675.       mov dx, 5351h;
  676.       int 21h;
  677.  
  678.       cmp al, 0ffh;
  679.       je notdv;
  680.     end;
  681.  
  682.     desqview := TRUE;
  683.  
  684. notdv:
  685.  
  686.     { Do we have an EGA or VGA?  If so, and we are not in monochrome mode
  687.        and we are not in DESQview then setup to draw a 'true' mouse cursor
  688.        on an EGA/VGA }
  689.     egavga := (vseg <> $b000) and (not desqview) and isegavga;
  690.  
  691.     if (egavga) then
  692.     begin
  693.       { We are going to use our 'true' mouse cursor and we need pixel
  694.          resolution, not character resolution from the mouse driver
  695.          (In text mode, the mouse driver only returns coordinates in multiples
  696.          of 8, which we don't want.  We want multiples of 1, i.e. pixel
  697.          resolution).  To get the mouse driver to return coordinates in pixel
  698.          resolution, we 'trick' it into thinking it's in graphics mode by
  699.          setting the low memory byte indicating mode to mode 6 (CGA 640x200x2).
  700.          Then we reset the mouse driver.  The mouse driver will get the video
  701.          mode then act as if it was in graphics mode, not text mode. }
  702.       savevmode := mem[$40:$49];
  703.       mem[$40:$49] := 6; { Does this work ?!?!?!?!? }
  704.  
  705.       { Reset driver for change in video mode to take effect. }
  706.       asm
  707.         sub ax,ax
  708.         int 33h
  709.       end;
  710.       { Now that we've tricked the mouse driver into a grapics mode thereby
  711.          causing it to give us pixel resolutions, put the old mode back. }
  712.       mem[$40:$49] := savevmode;
  713.     end;
  714.  
  715.     { Set up max x and y ranges. }
  716.  
  717.     maxx := mcols * 8 - 1; { Pixels horizontally }
  718.     maxy := mrows * points - 1; { Pixels vertically }
  719.  
  720.     asm
  721.       mov dx,[maxx]     { Pixels horizontally }
  722.       mov ax,7        { mouse driver function 7 -- set max x range }
  723.       sub cx,cx       { Minimum range }
  724.       int 33h
  725.  
  726.       mov dx,[maxy]     { Pixels veritcally }
  727.       mov ax,8        { mouse driver function 8 -- set max y range }
  728.       sub cx,cx       { Minimum range }
  729.       int 33h
  730.  
  731.     { Now install user routine }
  732.  
  733.       mov ax,cs
  734.       mov es,ax
  735.       mov dx, offset mousehandler
  736.     { Setup up bits for calling routine }
  737.       mov cx,LEFTBPRESS or LEFTBRELEASE or RIGHTBPRESS or RIGHTBRELEASE or MIDBPRESS or MIDBRELEASE or MOUSEMOVE;
  738.       mov ax,12       { Function 12 -- set user routine }
  739.       int 33h
  740.     end;
  741.     mousex := 0;
  742.     mousey := 0;
  743.     mousepx := 0;  { change by djm }
  744.     mousepy := 0;  { change by djm }
  745.     asm
  746.       mov cx,[mousex]   { xcoord }
  747.       mov dx,[mousey]   { ycoord }
  748.       mov ax,4    { mouse driver function 4 -- set mouse position }
  749.       int 33h
  750.     end;
  751.     MOUshow; { Call it twice just to make sure }
  752.  
  753.     dec(mousefreeze); { Handler can get into business, now }
  754.   end
  755. end;
  756.  
  757. {**************************}
  758. { 26-Oct-1990 - dk         }
  759. {                          }
  760. {  Hide the mouse cursor.  }
  761. {                          }
  762. {**************************}
  763. procedure MOUhide;
  764. { This function turns off the mouse cursor, the mouse still responds
  765.    to button presses }
  766. begin
  767.   if (not mouseinstalled) then
  768.     exit;
  769.  
  770.   inc(mousefreeze); { don't have the handler doing weird things }
  771.  
  772.   inc(mousehidden); { indicate it's hidden now }
  773.  
  774.   if (saved) then
  775.   begin
  776.     if (egavga) then
  777.       plotegavgacursor(0)
  778.     else
  779.       POKEATTRIB(oldmx, oldmy, oldword);
  780.     saved := FALSE;
  781.   end;
  782.  
  783.   dec(mousefreeze); { reactivate handler }
  784. end;
  785.  
  786. {**************************}
  787. { 26-Oct-1990 - dk         }
  788. {                          }
  789. {  Show the mouse cursor.  }
  790. {                          }
  791. {**************************}
  792. procedure MOUshow;
  793. begin
  794.   if (not mouseinstalled) then
  795.     exit;
  796.  
  797.   inc(mousefreeze); { don't have the handler doing weird things }
  798.  
  799.   { Just in case we were in a conditionalhide }
  800.   if (conditionalhidemouse) then
  801.   begin
  802.     { We were about to conditional hide, but we didn't, don't reactive
  803.        mouse cursor. }
  804.     conditionalhidemouse := FALSE;
  805.     dec(mousefreeze); { Reactivate handler }
  806.     exit;
  807.   end;
  808.  
  809.   if (mousehidden <> 0) then
  810.     dec(mousehidden)
  811.   else begin
  812.     dec(mousefreeze); { Reactivate handler }
  813.     exit;  { It isn't hidden! }
  814.   end;
  815.  
  816.   if (mousehidden <> 0) then
  817.   begin
  818.     dec(mousefreeze); { reactivate handler }
  819.     exit; { still hidden! }
  820.   end;
  821.  
  822.   { Draw mouse cursor }
  823.  
  824.   if (egavga) then
  825.     drawegavgacursor
  826.   else begin
  827.     oldword := PEEKATTRIB(mousex, mousey);
  828.     asm
  829.       mov AX,[oldword];  { Prepare to rotate attrib byte }
  830.       and al, 0f7h; { Clear high bit }
  831.       mov cl, 4   { We want to rotate 4 bits }
  832.       rol al, cl  { Rotate it }
  833.       mov newword,AX;
  834.     end;
  835.  
  836.     POKEATTRIB(mousex, mousey, newword); { Write out new mouse cursor }
  837.   end;
  838.  
  839.   oldmx := mousex;
  840.   oldmy := mousey;
  841.   saved := TRUE;
  842.  
  843.   dec(mousefreeze); { Reactivate handler }
  844. end;
  845.  
  846. {***********************************************************}
  847. { 27-Oct-1990 - dk                                          }
  848. {                                                           }
  849. {  Returns true if there is something in the mouse buffer.  }
  850. {                                                           }
  851. {***********************************************************}
  852. function MOUcheck:boolean;
  853. begin
  854.   MOUcheck := mbufin <> mbufout;
  855. end;
  856.  
  857. {************************************************************}
  858. { 26-Oct-1990 - dk                                           }
  859. {                                                            }
  860. {  Take a copy of the mouse event at the head of the queue.  }
  861. {                                                            }
  862. {************************************************************}
  863. procedure MOUpreview(var mouinforec:minforectype);
  864. begin
  865.   if (not mouseinstalled) then
  866.     exit;
  867.  
  868.   if (mbufin <> mbufout) then { if something is in buffer }
  869.     mouinforec := mbuf[mbufout]
  870.   else begin
  871.     { Nothing to pull, just report mouse position }
  872.     mouinforec.cx := mousex;
  873.     mouinforec.cy := mousey;
  874.     mouinforec.buttonstat := 0;
  875.     mouinforec.shiftstate := mem[0:$417];
  876.   end
  877. end;
  878.  
  879. {**************************************************************}
  880. { 26-Oct-1990 - dk                                             }
  881. {                                                              }
  882. {  Get (and remove) the mouse event at the head of the queue.  }
  883. {                                                              }
  884. {**************************************************************}
  885. procedure MOUget(var mouinforec:minforectype);
  886. begin
  887.   if (not mouseinstalled) then
  888.     exit;
  889.  
  890.   if (mbufin <> mbufout) then
  891.   begin { if something is in buffer }
  892.     if (@mouinforec <> nil) then
  893.       mouinforec := mbuf[mbufout];
  894.     mbufout := (mbufout + 1) mod MOUSEBUFFERSIZE;
  895.   end else begin
  896.     { Nothing to pull, just report mouse position }
  897.     mouinforec.cx := mousex;
  898.     mouinforec.cy := mousey;
  899.     mouinforec.buttonstat := 0;
  900.     mouinforec.shiftstate := mem[0:$417];
  901.   end
  902. end;
  903.  
  904. {************************************}
  905. { 26-Oct-1990 - dk                   }
  906. {                                    }
  907. {  Deinitialize the mouse routines.  }
  908. {                                    }
  909. {************************************}
  910. procedure MOUdeinit;
  911. begin
  912.   if (not mouseinstalled) then
  913.     exit;
  914.  
  915.   MOUhide;
  916.  
  917.   asm
  918.     sub ax,ax
  919.     int 33h
  920.   end;
  921. end;
  922.  
  923. {************************************************}
  924. { 26-Oct-1990 - dk                               }
  925. {                                                }
  926. {  Returns the bits for the button status info.  }
  927. {                                                }
  928. {************************************************}
  929. function MOUbuttonstatus:word;
  930. var
  931.   buts : word;
  932. begin
  933.  
  934.   if (not mouseinstalled) then
  935.   begin
  936.     MOUbuttonstatus := 0;
  937.     exit;
  938.   end;
  939.  
  940.   asm
  941.     mov ax,3
  942.     int 33h
  943.     mov buts,bx
  944.   end;
  945.   MOUbuttonstatus := buts;
  946. end;
  947.  
  948. {**********************************************************************}
  949. { 26-Oct-1990 - dk                                                     }
  950. {                                                                      }
  951. {  Hide the mouse *if* it enters a certain screen area, automatically. }
  952. {                                                                      }
  953. {**********************************************************************}
  954. procedure MOUconditionalhide(x1, y1, x2, y2:integer);
  955. begin
  956.   if (not mouseinstalled) then
  957.     exit;
  958.  
  959.   inc(mousefreeze); { hold the handler }
  960.  
  961.   if (mousehidden <> 0) then
  962.   begin
  963.     dec(mousefreeze); { reactivate handler }
  964.     exit; { already hidden! }
  965.   end;
  966.  
  967.   conditionalhidemouse := TRUE;
  968.  
  969.   dec(x1,2);
  970.   if (x1 < 0) then
  971.     x1 := 0;
  972.   dec(y1,2);
  973.   if (y1 < 0) then
  974.     y1 := 0;
  975.   inc(x2,2);
  976.   inc(y2,2);
  977.  
  978.   conx1 := x1;
  979.   cony1 := y1;
  980.   conx2 := x2;
  981.   cony2 := y2;
  982.  
  983.   if (mousex >= conx1) and (mousex <= conx2) and
  984.      (mousey >= cony1) and (mousey <= cony2) then
  985.   begin
  986.     conditionalhidemouse := FALSE; { We've already hidden it }
  987.     MOUhide; { turn it off now if it's there. }
  988.   end;
  989.  
  990.   dec(mousefreeze);
  991. end;
  992.  
  993. {*******************************************************}
  994. { 15-Mar-1991 - dk                    }
  995. {                            }
  996. {  Set the mouse cursor to a specific screen position.    }
  997. {                            }
  998. {*******************************************************}
  999. procedure MOUsetpos(x, y:integer);
  1000. begin
  1001.   if (not mouseinstalled) then
  1002.     exit;
  1003.  
  1004.   inc(mousefreeze);
  1005.  
  1006.   MOUhide;
  1007.  
  1008.   mousex := x;
  1009.   mousey := y;
  1010.   mousepx := mousex * 8;
  1011.   mousepy := mousey * points;
  1012.   asm
  1013.     mov cx, mousepx   { xcoord }
  1014.     mov dx, mousepy   { ycoord }
  1015.     mov ax, 4          { mouse driver function 4 -- set mouse position }
  1016.     int 33h
  1017.   end;
  1018.  
  1019.   MOUshow;
  1020.  
  1021.   dec(mousefreeze);
  1022. end;
  1023.  
  1024. end.
  1025.